﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Data;
using System.Diagnostics;
using Shrestha.Charts.Info;

namespace Shrestha.Charts.Graph
{
    public class PointsDrawer
    {
        private Bitmap _b;
        private const int MAXNUMBER = 50;
        private const int MAXCOLOR = 255;
        private const int BASECOLOR = 0;

        public String OutputFile { get; set; }
        public int Padding { get; set; }

        public void Save() { _b.Save(OutputFile); }

        private readonly DataView _dv;
        private readonly DrawingManager _dm;
        private readonly Runner _r;

        public Bitmap GetBitmap()
        {
            return _b;
        }

        public int Height { get; set; }
        public int Width { get; set; }

        public PointsDrawer(int width, int height)
        {
            this.Height = height;
            this.Width = width;
            this._b = new Bitmap(width, height);
            _b.SetResolution(299, 299);

        }

        public PointsDrawer(int width, int height, DataView dv, DrawingManager dm, Runner r)
        {
            this.Height = height;
            this.Width = width;
            this._b = new Bitmap(width+1, height+1);
            this._dv = dv;
            this._r = r;
            this._dm = dm;
        }

        private Color GetColor(int maxval, int minval, int currentval, Color cbase)
        {
            return Color.FromArgb((byte)(((currentval - minval) * 128 / (maxval - minval))+128), cbase.R, cbase.G, cbase.B);
        }

        private Color GetColor(int maxval, int minval, int currentval, Color a, Color b)
        {
            double coeff = (double)(currentval - minval) / (double)(maxval - minval);
            return Color.FromArgb(0xff, (int)(coeff * (b.R - a.R) + a.R), (int)(coeff * (b.G - a.G) + a.G), (int)(coeff * (b.G - a.G) + a.G));
        }

        private Color GetColor(int maxval, int minval, int currentval, Color a, Color b, double pow)
        {
            int maxcolor = MAXCOLOR - BASECOLOR;
            double coeff = (double)(currentval - minval) / (double)(maxval - minval);
            double c = (Math.Pow(maxcolor, 1 / pow) * (currentval - minval)) / (maxval - minval);
            c = Math.Pow(c, pow);
            c = (c > maxcolor) ? maxcolor : c;
            return Color.FromArgb((byte)((int)c + BASECOLOR), (int)(coeff * (b.R - a.R) + a.R), (int)(coeff * (b.G - a.G) + a.G), (int)(coeff * (b.G - a.G) + a.G));
        }

        private Color GetColor(int maxval, int minval, int currentval, Color cbase, double pow)
        {
            int maxcolor = MAXCOLOR - BASECOLOR;
            double c = (Math.Pow(maxcolor, 1 / pow) * (currentval - minval)) / (maxval - minval);
            c = Math.Pow(c,pow);
            c = (c > maxcolor) ? maxcolor : c;
            return Color.FromArgb((byte)((int)c + BASECOLOR),cbase.R, cbase.G, cbase.B);
        }

        private Color GetColor(int maxval, int minval, int currentval)
        {
            //// Laos
            if (currentval < 250) return Color.LightBlue;//FromArgb(0xff, 0xb0, 0xc4, 0xde);
            else if (currentval < 1000) return Color.FromArgb(0xff, 0x41, 0x69, 0xE1);
            else if (currentval < 2500) return Color.OrangeRed;//.Tomato;
            else return Color.DarkRed;//Brown

            // Afghan
            //if (currentval < 1) return Color.Sienna;
            //else if (currentval < 5) return Color.FromArgb(0xff, 0x41, 0x69, 0xE1);
            //else if (currentval < 10) return Color.Orange;
            //else return Color.Red

        }

        private void HandlePixel(int x, int y, Color c)
        {
            if(x < Width && y < Height && x >= 0 && y >=0)
                _b.SetPixel(x, y, c);
        }

        public void Draw()
        {
            DataTable dt = _dv.ToTable();
            int mingval = int.MaxValue;
            int maxgval = int.MinValue;
            int c;
            double x, y;
            Stopwatch s = new Stopwatch();

            LegendEntry le1 = new LegendEntry() { color = Color.LightBlue, misc = "< 250" };
            LegendEntry le2 = new LegendEntry() { color = Color.FromArgb(0xff, 0x41, 0x69, 0xE1), misc = "250 - 1000" };
            LegendEntry le3 = new LegendEntry() { color = Color.OrangeRed, misc = "1000 - 2500" };
            LegendEntry le4 = new LegendEntry() { color = Color.DarkRed, misc = " > 2500" };

            //LegendEntry le1 = new LegendEntry() { color = Color.Tomato, misc = "Enemy Action" };
            //LegendEntry le2 = new LegendEntry() { color = Color.DarkRed, misc = "Explosive Hazard" };
            //LegendEntry le3 = new LegendEntry() { color = Color.FromArgb(0xff, 0x41, 0x69, 0xE1), misc = "Friendly Action" };
            //LegendEntry le4 = new LegendEntry() { color = Color.LightBlue, misc="Non-combat event" };

            Legend l = new Legend();
            l.Add(le1);
            l.Add(le2);
            l.Add(le3);
            l.Add(le4);

            _r.legend = l;

            if (_r.ContainsGradient)
            {
                dt.Columns.Add("t", typeof(int));
                foreach (DataRow dr in dt.Rows)
                {
                    int val = int.Parse(dr[_r.GradientName].ToString());
                    dr["t"] = val;
                    mingval = Math.Min(mingval, val);
                    maxgval = Math.Max(maxgval, val);
                }

                dt.DefaultView.Sort = "t asc";
                dt = dt.DefaultView.ToTable();


                s.Start();
                foreach (DataRow dr in dt.Rows)
                {
                    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                    c = (int)dr["t"];
                    //Point((int)x, (int)y, GetColor(maxgval, mingval, c));
                    Point((int)x, (int)y, GetColor(maxgval, mingval, c, Color.Red, 0.2));
                    //Point((int)x, (int)y, GetColor(maxgval, mingval,c,Color.Navy, Color.OrangeRed, 0.18));
                }
                s.Stop();
            }
            else
            {
                int p;
                s.Start();
                //foreach (DataRow dr in dt.Rows)
                //{
                //    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                //    switch ((String)dr["Type"])
                //    {
                //        case "Friendly Action":
                //            p = 1;
                //            break;
                //        case "Enemy Action":
                //            p = 2;
                //            break;
                //        case "Explosive Hazard":
                //            p = 3;
                //            break;
                //        default:
                //            p = 0;
                //            break;
                //    }
                //    Point((int)x, (int)y, GetColor(maxgval, mingval, p));
                //}


                //foreach (DataRow dr in dt.Select("Type='Explosive Hazard'"))
                //{
                //    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                //    Point((int)x, (int)y, Color.DarkRed);
                //}

                //foreach (DataRow dr in dt.Select("Type='Enemy Action'"))
                //{
                //    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                //    Point((int)x, (int)y, Color.Tomato);
                //}
                //foreach (DataRow dr in dt.Select("Type='Friendly Action'"))
                //{
                //    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                //    Point((int)x, (int)y, Color.FromArgb(0xff, 0x41, 0x69, 0xE1));
                //}
                //foreach (DataRow dr in dt.Select("Type='Non-Combat Event'"))
                //{
                //    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                //    Point((int)x, (int)y, Color.LightBlue);
                //}

                s.Start();

                //var results = (from row in dt.AsEnumerable()
                //               group row by new
                //               {
                //                   Latitude = row.Field<double>(_r.LatName),
                //                   Longitude = row.Field<double>(_r.LngName)
                //               }
                //                   into g
                //                   select new
                //                   {
                //                       Latitude = g.Key.Latitude,
                //                       Longitude = g.Key.Longitude,
                //                       Date = g.Select(z => z.Field<DateTime>(_r.DateTimeName)),
                //                       t = g.Count()
                //                   }).Distinct().ToList();
                //mingval = (from r in results select r.t).Min();
                //maxgval = (from r in results select r.t).Max();

                //foreach (var dr in results)
                //{
                //    _dm.GetCanvasCoordinates(dr.Latitude, dr.Longitude, dr.Date, out x, out y);
                //    Point((int)x, (int)y, GetColor(maxgval, mingval, (int)dr.t, Color.Red, 0.2));
                //}



                foreach (DataRow dr in dt.Rows)
                {
                    _dm.GetCanvasCoordinates((double)dr[_r.LatName], (double)dr[_r.LngName], (DateTime)dr[_r.DateTimeName], out x, out y);
                    Point((int)x, (int)y, Color.Tomato);
                }

                s.Stop();
            }
            Console.WriteLine(s.Elapsed);
        }

        private void Point(int x, int y, Color color)
        {
            HandlePixel(x - Padding, y - Padding, color);
            HandlePixel(x - Padding, y, color);
            HandlePixel(x - Padding, y + Padding, color);

            HandlePixel(x, y - Padding, color);
            HandlePixel(x, y, color);
            HandlePixel(x, y + Padding, color);

            HandlePixel(x + Padding, y - Padding, color);
            HandlePixel(x + Padding, y, color);
            HandlePixel(x + Padding, y + Padding, color);
        }


        
    }
}
